﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO.Ports;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace TempMonitor
{
    public partial class Version : Form
    {
        public Version()
        {
            InitializeComponent();
        }

        byte deviceAddr = 0;
        private void Version_Load(object sender, EventArgs e)
        {
            deviceAddr = modbus.DeviceAddr;
            label5.Text = "当前设备地址：" + deviceAddr.ToString();
            label4.Text = "选择串口：" + modbus.PortName;
        }

        private bool SendReadHoldingRegisterDataAndVerify(byte[] sendData, UInt16 registerStartAddr, UInt16 registerCount, ref byte recDataLen, ref byte[] receiveData)
        {
            serialPort1.ReadExisting();//清空缓存
            serialPort1.Write(sendData, 0, sendData.Length);

            /* 返回的数据
             * 从机地址	 功能号	数据字节个数(1字节)	字节数据(寄存器先发送的先回来)	CRC校验 */
            int receiveDataLength = 5 + registerCount * 2;

            for (int i = 0; i < (2 + registerCount); i++)
            {
                Thread.Sleep(100);
                int len = serialPort1.BytesToRead;
                if (len >= receiveDataLength)
                {
                    byte[] readData = new byte[len];
                    serialPort1.Read(readData, 0, len);

                    UInt16 crc = modbus.Get_Crc_16(readData, receiveDataLength - 2);
                    UInt16 crcData = (UInt16)(readData[receiveDataLength - 1] + readData[receiveDataLength - 2] * 256);
                    if (crc != crcData)
                    {
                        string tmp = string.Format("CRC:{0:X},CRC check:{0:X}", crcData, crc);
                        Log.WriteLog("返回的CRC不对--" + tmp);
                        return false;
                    }
                    if (readData[0] != deviceAddr || readData[1] != modbus.ReadHoldingRegister)
                    {
                        Log.WriteLog("返回的设备地址或者功能码不对。");
                        return false;
                    }
                    recDataLen = readData[2];
                    Array.Copy(readData, 3, receiveData, 0, recDataLen);
                    Log.WriteLog("返回的数据长度："+ recDataLen.ToString());
                    return true;
                }
            }
            Log.WriteLog("没有从串口获取到数据。");
            return false;
        }

        private bool OpenSerial()
        {
            if (!serialPort1.IsOpen)
            {
                try
                {
                    string portName = modbus.PortName;
                    if (portName != "")
                    {
                        //串口的设置
                        serialPort1.PortName = portName;
                        serialPort1.BaudRate = 9600;
                        serialPort1.Parity = Parity.None;
                        serialPort1.DataBits = 8;
                        serialPort1.StopBits = StopBits.One;

                        serialPort1.Open();
                    }
                    else
                    {
                        this.Invoke(new Action(() =>
                        {
                            label7.Text = "串口未选择";
                        }));
                        Log.WriteLog("串口未选择:");
                        return false;
                    }
                }
                catch (Exception msg)
                {
                    this.Invoke(new Action(() =>
                    {
                        label7.Text = msg.Message;
                    }));
                    Log.WriteLog("打开串口异常:");
                    Log.WriteLog(msg.Message);
                    Log.WriteLog(msg.StackTrace);
                    serialPort1.Close();
                    return false;
                }
            }
            Log.WriteLog("串口已打开。");
            this.Invoke(new Action(() =>
            {
                label7.Text = "串口已打开。";
            }));
            return true;
        }

        private bool ReadVersionFromDevice(ref byte[] version)
        {
            const UInt16 registerStartAddr = 50;
            Log.WriteLog("开始从设备里读取版本。");
            byte[] data = modbus.GetDataForReadHoldingRegister(deviceAddr, registerStartAddr, 2);
            byte[] receiveData = new byte[4]; //只有4个字节
            byte receiveDataLength = 0;
            bool returnValue = SendReadHoldingRegisterDataAndVerify(data, registerStartAddr, 2, ref receiveDataLength, ref receiveData);
            if (returnValue == true && receiveDataLength == 4)
            {
                Array.Copy(receiveData, version, 4);
                Log.WriteLog("设备硬件版本是:" + receiveData[2].ToString() + "." + receiveData[3].ToString());
                Log.WriteLog("设备软件版本是:" + receiveData[0].ToString() + "." + receiveData[1].ToString());
            }
            else
            {
                Log.WriteLog("读取版本：数据长度不对或没有收到数据。");
                return false;
            }
            return returnValue;
        }

        private void button1_Click(object sender, EventArgs e)
        {
            try
            {
                if (OpenSerial() == true)
                {
                    label7.Text = "正在读取设备版本信息，请稍候...";
                    byte[] version = new byte[4];

                    if (ReadVersionFromDevice(ref version) == true)
                    {
                        label1.Text = "设备硬件版本：" + version[2].ToString() + "." + version[3].ToString();
                        label2.Text = "设备软件版本：" + version[0].ToString() + "." + version[1].ToString();
                        label7.Text = "成功读取到数据。";
                    }
                    else
                    {
                        label7.Text = "无法读取到数据。";
                    }
                    
                    serialPort1.Close();

                }
                else
                {
                    Log.WriteLog("打开串口出错！");
                    label7.Text = "打开串口出错！";
                    serialPort1.Close();
                }
            }
            catch (Exception ex)
            {
                Log.WriteLog(ex.Message);
                Log.WriteLog(ex.StackTrace);
                serialPort1.Close();
            }
        }
    }
}
